/*
 * Kobold2D™ --- http://www.kobold2d.org
 *
 * Copyright (c) 2010-2011 Steffen Itterheim. 
 * Released under MIT License in Germany (LICENSE-Kobold2D.txt).
 */

#import "PhysicsLayer.h"
#import "Box2DDebugLayer.h"

@interface PhysicsLayer (PrivateMethods)

@end

@implementation PhysicsLayer
-(id) init
{
	if ((self = [super init]))
	{
		// Use the orthogonal tileset for the little boxes
        [self initWorld];
		//[self scheduleUpdate];
        //comment this code to deactive accelerometer
	}

	return self;
}

-(void) enableBox2dDebugDrawing
{
	const BOOL useBox2DDebugLayer = YES;
	
	float debugDrawScaleFactor = 1.0f;
	debugDrawScaleFactor = [[CCDirector sharedDirector] contentScaleFactor];
	debugDrawScaleFactor *= PTM_RATIO;

	UInt32 debugDrawFlags = 0;
	debugDrawFlags += b2Draw::e_shapeBit;
	debugDrawFlags += b2Draw::e_jointBit;
    if (useBox2DDebugLayer)
	{
		Box2DDebugLayer* debugLayer = [Box2DDebugLayer debugLayerWithWorld:world
																  ptmRatio:PTM_RATIO
																	 flags:debugDrawFlags];
		[self addChild:debugLayer z:100];
	}
	else
	{
		debugDraw = new GLESDebugDraw(debugDrawScaleFactor);
		if (debugDraw)
		{
			debugDraw->SetFlags(debugDrawFlags);
			world->SetDebugDraw(debugDraw);
		}
	}
}


#pragma mark - create sections
/****************************************************
/init physic world
****************************************************/
- (void)initWorld
{
    CCLOG(@"%@ init", NSStringFromClass([self class]));
    glClearColor(0.1f, 0.0f, 0.2f, 1.0f);		
    // Construct a world object, which will hold and simulate the rigid bodies.
    b2Vec2 gravity = b2Vec2(0.0f, -10.0f);
    world = new b2World(gravity);
    world->SetAllowSleeping(YES);
    world->SetContinuousPhysics(NO);
    
    // this line to draw debug info
    //[self enableBox2dDebugDrawing];
    contactListener = new ContactListener();
    world->SetContactListener(contactListener);
    
}
/****************************************************
/create wolrd with no plane
****************************************************/
- (void)createWorldWithSpace
{
    CGSize screenSize = [CCDirector sharedDirector].winSize;

    NSString* message = @"Create world with space !";
    
    CCLabelTTF* label = [CCLabelTTF labelWithString:message fontName:@"Marker Felt" fontSize:32];
    [self addChild:label];
    [label setColor:ccc3(222, 222, 255)];
    label.position = CGPointMake(screenSize.width / 2, screenSize.height - 50);
}

/****************************************************
/create world with screen edge bounding
****************************************************/
- (void)createWorldwithFixScreen
{
    // for the screenBorder body we'll need these values
    CGSize screenSize = [CCDirector sharedDirector].winSize;
    float widthInMeters = screenSize.width / PTM_RATIO;
    float heightInMeters = screenSize.height / PTM_RATIO;
    b2Vec2 lowerLeftCorner = b2Vec2(0, 0);
    b2Vec2 lowerRightCorner = b2Vec2(widthInMeters, 0);
    b2Vec2 upperLeftCorner = b2Vec2(0, heightInMeters);
    b2Vec2 upperRightCorner = b2Vec2(widthInMeters, heightInMeters);
    
    // Define the static container body, which will provide the collisions at screen borders.
    b2BodyDef screenBorderDef;
    screenBorderDef.position.Set(0, 0);
    b2Body* screenBorderBody = world->CreateBody(&screenBorderDef);
    b2EdgeShape screenBorderShape;
    
    // Create fixtures for the four borders (the border shape is re-used)
    screenBorderShape.Set(lowerLeftCorner, lowerRightCorner);
    screenBorderBody->CreateFixture(&screenBorderShape, 0);
    screenBorderShape.Set(lowerRightCorner, upperRightCorner);
    screenBorderBody->CreateFixture(&screenBorderShape, 0);
    screenBorderShape.Set(upperRightCorner, upperLeftCorner);
    screenBorderBody->CreateFixture(&screenBorderShape, 0);
    screenBorderShape.Set(upperLeftCorner, lowerLeftCorner);
    screenBorderBody->CreateFixture(&screenBorderShape, 0);
    
    //log to debug
    NSString* message = @"Create world with fix screen !";

    CCLabelTTF* label = [CCLabelTTF labelWithString:message fontName:@"Marker Felt" fontSize:32];
    [self addChild:label];
    [label setColor:ccc3(0, 255, 255)];
    label.position = CGPointMake(screenSize.width / 2, screenSize.height - 50);

}
/****************************************************
/create wold with plane and width
****************************************************/
- (void)createWorldWithPlane:(float)width pos:(CGPoint)pos
{
    CGSize screenSize = [CCDirector sharedDirector].winSize;
    //float widthInMeters = width / PTM_RATIO;
    b2Vec2 lowerLeftCorner = [MathHelper toMeters:pos];
    b2Vec2 lowerRightCorner = [MathHelper toMeters:ccp(pos.x + width , pos.y)];
     
    // Define the static container body, which will provide the collisions at screen borders.
    b2BodyDef screenBorderDef;
    //screenBorderDef.position.Set(pos.x/PTM_RATIO, pos.y/PTM_RATIO);
    b2Body* screenBorderBody = world->CreateBody(&screenBorderDef);
    b2EdgeShape screenBorderShape;
    // Create fixtures for the four borders (the border shape is re-used)
    screenBorderShape.Set(lowerLeftCorner, lowerRightCorner);
    screenBorderBody->CreateFixture(&screenBorderShape, 0);

    //print to screen message
    NSString* message = @"Create world with plane !";

    
    CCLabelTTF* label = [CCLabelTTF labelWithString:message fontName:@"Marker Felt" fontSize:32];
    [self addChild:label];
    [label setColor:ccc3(222, 222, 255)];
    label.position = CGPointMake(screenSize.width / 2, screenSize.height - 50);
}


#pragma mark - action utilities
/****************************************************
/acton explode all body in world
****************************************************/
/*-(void) explodeSpritesInRadius:(float)radius
                     withForce:(float)maxForce
                      position:(CGPoint)pos
                       suction:(bool)doSuction
{
    BodiesInAABBCallback callback;
    b2AABB aabb;
    
    aabb.lowerBound = [MathHelper toMeters:ccp(pos.x - radius, pos.y - radius)];
    aabb.upperBound = [MathHelper toMeters:ccp(pos.x + radius, pos.y + radius)];
    
    world->QueryAABB(&callback, aabb);
    
    std::map<b2Body*, b2Fixture*>::iterator it;
    
    for(it = callback.queryInfo.begin(); it != callback.queryInfo.end(); ++it)
    {
        b2Body* b = (*it).first;    
        
		b2Vec2 b2TouchPosition = [MathHelper toMeters:pos];
		b2Vec2 b2BodyPosition = b2Vec2(b->GetPosition().x, b->GetPosition().y);
        
		float maxDistance = radius/PTM_RATIO;
		CGFloat distance = 0.0f;
		CGFloat strength = 0.0f;
		float force = 0.0f;
		CGFloat angle = 0.0f;
        
		if(doSuction)//incase suction 
		{
			distance = b2Distance(b2BodyPosition, b2TouchPosition);
			if(distance > maxDistance) 
                distance = maxDistance - 0.01;
			// Get the strength
			//strength = distance / maxDistance; // Uncomment and reverse these two. and ones further away will get more force instead of less
			strength = (maxDistance - distance) / maxDistance; // This makes it so that the closer something is - the stronger, instead of further
			force  = strength * maxForce;
            
			// Get the angle
			angle = atan2f(b2TouchPosition.y - b2BodyPosition.y, b2TouchPosition.x - b2BodyPosition.x);
            b->ApplyForce(b2Vec2(cosf(angle) * force, sinf(angle) * force), b->GetPosition());
		}
		else//incase not suction
		{
			distance = b2Distance(b2BodyPosition, b2TouchPosition);
			if(distance > maxDistance) distance = maxDistance - 0.01;
            
			strength = (maxDistance - distance) / maxDistance;
			force = strength * maxForce;
			angle = atan2f(b2BodyPosition.y - b2TouchPosition.y, b2BodyPosition.x - b2TouchPosition.x);
            b->ApplyForce(b2Vec2(cosf(angle) * force, sinf(angle) * force), b->GetPosition());
		}
	}
}*/


#pragma mark - util method

#pragma mark - draw section
/****************************************************
/acton draw --> draw all logic object from bo2D world
****************************************************/
-(void) draw
{
	[super draw];

	if (debugDraw)
	{
		ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position);
		kmGLPushMatrix();
		world->DrawDebugData();	
		kmGLPopMatrix();
	}
}

#pragma mark - dealloc section
-(void) dealloc
{
	delete contactListener;
	delete world;
	[super dealloc];
}

@end
